﻿using System;
using System.Net;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace PubSub.S2
{
    public class RedisPubSubProvider
    {
        private static ConnectionMultiplexer PubConnectionMutiplCon = null;
        private static ConnectionMultiplexer SubConnectionMutiplCon = null;

        public static void Publish(RedisPubSubMessage message)
        {
            try
            {
                if (PubConnectionMutiplCon == null)
                {
                    var redis = ConnectionRedis(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6379), string.Empty);
                    PubConnectionMutiplCon = redis;
                }

                var sub = PubConnectionMutiplCon.GetSubscriber();

                var channelName = FuncTypeFactory.GetChannelString(message.FuncType);
                var redisChannel = new RedisChannel(channelName, RedisChannel.PatternMode.Auto);
                var body = JsonConvert.SerializeObject(message);
                sub.Publish(redisChannel, body);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        public static void Subscribe(BaseHandler handler)
        {
            if (SubConnectionMutiplCon == null)
            {
                var redis = ConnectionRedis(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6379), string.Empty);
                SubConnectionMutiplCon = redis;
            }

            var sub = SubConnectionMutiplCon.GetSubscriber();

            var funcType = handler.FuncType;
            var channelName = FuncTypeFactory.GetChannelString(funcType);
            var redisChannel = new RedisChannel(channelName, RedisChannel.PatternMode.Auto);

            sub.Subscribe(redisChannel,
                (channel, redisValue) =>
                {
                    //Console.WriteLine($"channel:{channel},\tmessage:{redisValue}");
                    Console.WriteLine($"{redisValue}");
                    try
                    {
                        if (redisValue.HasValue)
                        {
                            var json = redisValue.ToString();
                            if (!string.IsNullOrEmpty(json))
                            {
                                var message = JsonConvert.DeserializeObject<RedisPubSubMessage>(json);
                                if (message == null)
                                {
                                    //todo ？
                                }
                                else
                                {
                                    handler.Execute(message);
                                }

                                return;
                            }
                        }

                        handler.Execute(null);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                });
        }


        private static ConnectionMultiplexer ConnectionRedis(EndPoint endPoint, string password)
        {
            var configurationOptions = new ConfigurationOptions
            {
                EndPoints =
                {
                    endPoint
                    //{"127.0.0.1",6379}
                },
                //注释ServiceName，非哨兵模式会报错，哨兵模式已经废弃，目前只支持单节点和集群模式
                //ServiceName = endPoint.ToString(),
                AllowAdmin = true,
                //Password = password,
                SyncTimeout = (int) TimeSpan.FromSeconds(value: 60).TotalMilliseconds,
            };
            if (!string.IsNullOrWhiteSpace(password))
            {
                configurationOptions.Password = password;
            }

            var connectionMultiplexer = ConnectionMultiplexer.Connect(configurationOptions);
            connectionMultiplexer.PreserveAsyncOrder = false;
            connectionMultiplexer.ConnectionRestored += ConnectionMultiplexerOnConnectionRestored;
            connectionMultiplexer.ConnectionFailed += ConnectionMultiplexerOnConnectionFailed;
            return connectionMultiplexer;
        }

        static void ConnectionMultiplexerOnConnectionRestored(object sender,
            ConnectionFailedEventArgs connectionFailedEventArgs)
        {
        }

        static void ConnectionMultiplexerOnConnectionFailed(object sender,
            ConnectionFailedEventArgs connectionFailedEventArgs)
        {
        }
    }
}